/*
 * @(#)XfslAlgorithm.java        1.0 2000/05/09
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfsl.model;

import xfuzzy.lang.*;
import xfuzzy.xfds.XfdsDataSet;


/**
 * Clase abstracta que describe un algoritmo de aprendizaje
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public abstract class XfslAlgorithm implements IXfslAlgorithmConstants, Cloneable {

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Indica si se encuentra inicializ�ndose
	 */
	protected boolean init = true;

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Identificador del algoritmo en la interfaz gr�fica
	 */
	public static String getName(int code) throws XflException {
		switch(code) {
			case INCREMENTALBACKPROP: return "Incremental Backpropagation";
			case BACKPROP: return "Backpropagation";
			case BACKPROPMOM: return "Backprop with Momentum";
			case ADAPTLEARNRATE: return "Adaptive Learning Rate";
			case ADAPTSTEPSIZE: return "Adaptive Step Size";
			case MANHATTAN: return "Manhattan";
			case QUICKPROP: return "QuickProp";
			case RPROP: return "RProp";

			case STEEPEST: return "Steepest Descent";
			case POLAK_RIBIERE: return "Polak-Ribiere";
			case FLETCHER_REEVES: return "Fletcher-Reeves";
			case HESTENES_STIEFEL: return "Hestenes-Stiefel";
			case ONE_STEP_SECANT: return "One Step Secant";
			case SCALED: return "Scaled Conjugate Gradient";

			case DFP: return "Davidon-Fletcher-Powell";
			case BFGS: return "Broyden-Fletcher-Goldfarb-Shanno";
			case MARQUARDT: return "Marquardt-Levenberg";
			case GAUSS: return "Gauss-Newton";
			
			case BLIND: return "Blind Search";
			case SIMPLEX: return "Downhill Simplex";
			case POWELL: return "Powell's";

			case LINEAR_ANNEALING: return "Linear Simulated Annealing";
			case EXPONENTIAL_ANNEALING: return "Exponential Simulated Annealing";
			case CLASSICAL_ANNEALING: return "Classical Simulated Annealing";
			case FAST_ANNEALING: return "Fast Simulated Annealing";
			case ADAPTIVE_ANNEALING: return "Adaptive Simulated Annealing";

			default: throw new XflException(28);
		}
	}
	
	/**
	 * Verifica el valor de un p�rametro de un cierto tipo
	 */
	public static final double test(double param, int tst) throws XflException {
		boolean good = true;
		switch(tst) {
		case POSITIVE: good = (param>0); break;
		case MOMENTUM: good = (param > 0 && param <= 1); break;
		case INCREASE: good = (param > 1); break;
		case DECREASE: good = (param > 0 && param < 1); break;
		case REDUCE:   good = (param > 0 && param <= 0.5); break;
		}
		if(!good) throw new XflException(26);
		return param;
	}

	/**
	 * Duplica el objeto
	 */
	public Object clone() {
		try { return super.clone(); }
		catch(CloneNotSupportedException e) { return null; }
	}

	/**
	 * Marca la reinicializacion del algoritmo
	 */
	public void reinit() {
		this.init = true;
	}

	/**
	 * Devuelve el identificador de la interfaz gr�fica
	 */
	public String getName() {
		try { return getName( getCode() ); }
		catch(Exception ex) {}
		return "";
	}

	/**
	 * Descripci�n del algoritmo en el fichero de configuraci�n
	 */
	public String toXML() {
		String eol = System.getProperty("line.separator", "\n");
		String name = "";
		try { name = getParseName( getCode() ); } catch(Exception ex) {}
		String xml = "\t\t<algorithm name=\""+name+"\">"+eol;
		XfslAlgorithmParam[] param = getParams();
		for(int i=0; i<param.length; i++) {
			xml += "\t\t\t<param value=\""+param[i].getValue()+"\"></param>"+eol;
		}
		xml += "\t\t</algorithm>"+eol;
		return xml;
	}

	/**
	 * Devuelve el c�digo de identificaci�n del algoritmo
	 */
	public abstract int getCode();

	/**
	 * Actualiza los par�metros de configuraci�n del algoritmo
	 */
	public abstract void setParameters(double[] param) throws XflException;

	/**
	 * Obtiene los par�metros de configuraci�n del algoritmo
	 */
	public abstract XfslAlgorithmParam[] getParams();

	/**
	 * Ejecuta una iteraci�n del algoritmo
	 */
	public abstract XfslEvaluation iteration(Specification spec, XfdsDataSet p,
			XfslErrorFunction ef) throws XflException;

	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Identificador del algoritmo en el fichero de configuraci�n
	 */
	protected String getParseName(int code) throws XflException {
		switch(code) {
			case INCREMENTALBACKPROP: return "IncrementalBackprop";
			case BACKPROP: return "Backpropagation";
			case BACKPROPMOM: return "Backprop_with_momentum";
			case ADAPTLEARNRATE: return "Adaptive_learning_rate";
			case ADAPTSTEPSIZE: return "Adaptive_step_size";
			case MANHATTAN: return "Manhattan";
			case QUICKPROP: return "Quickprop";
			case RPROP: return "Rprop";
			
			case STEEPEST: return "Steepest_descent";
			case POLAK_RIBIERE: return "Polak_Ribiere";
			case FLETCHER_REEVES: return "Fletcher_Reeves";
			case HESTENES_STIEFEL: return "Hestenes_Stiefel";
			case ONE_STEP_SECANT: return "One_Step_Secant";
			case SCALED: return "Scaled_conjugate_gradient";

			case DFP: return "Davidon_Fletcher_Powell";
			case BFGS: return "Broyden_Fletcher_Goldfarb_Shanno";
			case MARQUARDT: return "Marquardt";
			case GAUSS: return "Gauss_Newton";
			
			case BLIND: return "Blind_search";
			case SIMPLEX: return "Simplex";
			case POWELL: return "Powell";
			
			case LINEAR_ANNEALING: return "Linear_Simulated_Annealing";
			case EXPONENTIAL_ANNEALING: return "Exponential_Simulated_Annealing";
			case CLASSICAL_ANNEALING: return "Classical_Simulated_Annealing";
			case FAST_ANNEALING: return "Fast_Simulated_Annealing";
			case ADAPTIVE_ANNEALING: return "Adaptive_Simulated_Annealing";

		default: throw new XflException(28);
		}
	}

}
